using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Disposables;
using System.Threading;
using System.Threading.Tasks;
using System.Reactive;
using ReactiveChannelMessaging.Communication;
using ReactiveChannelMessaging.Examples;

namespace ReactiveChannelMessaging.WinForms
{
    /// <summary>
    /// 响应等待辅助类，提供基于Rx.NET的异步等待响应功能
    /// </summary>
    public static class WaitForResponseHelper
    {
        /// <summary>
        /// 等待并接收指定长度的数据，支持超时和取消。
        /// </summary>
        /// <param name="communicationManager">通信管理器实例</param>
        /// <param name="portName">串口名称</param>
        /// <param name="expectedResponseLength">期望接收的数据长度</param>
        /// <param name="timeout">等待超时时间（毫秒）</param>
        /// <param name="cancellationToken">用于取消操作的令牌</param>
        /// <returns>一个元组，包含成功标志和接收到的数据</returns>
        public static async Task<(bool success, byte[] data)> WaitForResponseAsync(
            CommunicationManager communicationManager,
            string portName,
            int expectedResponseLength,
            int timeout,
            CancellationToken cancellationToken = default)
        {
            try
            {
                // 获取串口通信实例
                if (communicationManager == null || !communicationManager.SerialPorts.TryGetValue(portName, out var serialComm))
                {
                    return (false, Array.Empty<byte>());
                }

                // 将 byte[] 展平为 byte，然后每 10 毫秒收集一次数据。
                var callObservable = serialComm.ReceivedData
                    .SelectMany(dataMessage => dataMessage.Data.Select(b => b))
                    .Buffer(TimeSpan.FromMilliseconds(10)) // 每 10 毫秒收集一次数据
                    .Scan(
                        new List<byte>(),
                        (acc, b) =>
                        {
                            acc.AddRange(b);
                            return acc;
                        }
                    )
                    .Where(combinedBuffer => combinedBuffer.Count >= expectedResponseLength)
                    .Timeout(TimeSpan.FromMilliseconds(timeout)) // 设置超时
                    .TakeUntil(Observable.Create<Unit>(observer =>
                    {
                        // 注册取消令牌回调
                        var registration = cancellationToken.Register(() =>
                        {
                            observer.OnNext(Unit.Default);
                            observer.OnCompleted();
                        });
                        return Disposable.Create(() => registration.Dispose());
                    }));

                // 等待 Observable 发出值
                var result = await callObservable.FirstOrDefaultAsync();
                if (result != null && result.Count >= expectedResponseLength)
                {
                    // 成功接收到指定长度的数据，返回成功标志和数据数组
                    // 只返回期望长度的数据
                    var responseData = result.Take(expectedResponseLength).ToArray();
                    return (true, responseData);
                }
                else
                {
                    // 未接收到指定长度的数据（可能是超时或取消），返回失败标志和空数组
                    return (false, Array.Empty<byte>());
                }
            }
            catch (TimeoutException)
            {
                // 发生超时，返回失败标志和空数组
                return (false, Array.Empty<byte>());
            }
            catch (OperationCanceledException)
            {
                // 操作被取消，返回失败标志和空数组
                return (false, Array.Empty<byte>());
            }
            catch (Exception)
            {
                // 其他异常，返回失败标志和空数组
                return (false, Array.Empty<byte>());
            }
        }
    }
}